<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>即时通讯应用</title>
    <script src="https://unpkg.com/vue@3.5.0/dist/vue.global.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.7/signalr.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js" integrity="sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" integrity="sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <style>

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f5f5f5;
            height: 100vh;
            margin: 0;
        }

        .app-container {
            display: flex;
            height: 100vh;
        }

        .chat-container {
            display: flex;
            height: 100%;
            width: 100%;
            max-width: 1400px;
            margin: 0 auto;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            background-color: white;
        }

        .user-profile {
            width: 280px;
            background-color: #2c3e50;
            color: white;
            padding: 20px;
            display: flex;
            flex-direction: column;
            border-right: 1px solid #34495e;
        }

        .profile-header {
            text-align: center;
            margin-bottom: 20px;
        }

        .avatar {
            width: 100px;
            height: 100px;
            border-radius: 50%;
            margin: 0 auto 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 36px;
            font-weight: bold;
            color: white;
            background-color: #3498db;
        }

        .user-name {
            font-size: 1.2rem;
            margin-bottom: 5px;
        }

        .user-email {
            color: #bdc3c7;
            font-size: 0.9rem;
            margin-bottom: 15px;
        }

        .user-status {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            padding: 8px;
            border-radius: 20px;
            background-color: rgba(255, 255, 255, 0.1);
            margin-bottom: 20px;
        }

        .status-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
        }

        .status-indicator.online {
            background-color: #2ecc71;
            box-shadow: 0 0 8px #2ecc71;
        }

        .status-indicator.offline {
            background-color: #95a5a6;
        }

        .profile-details {
            margin-top: 20px;
        }

        .detail-item {
            padding: 12px 0;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        }

        .detail-label {
            font-size: 0.8rem;
            color: #bdc3c7;
            margin-bottom: 4px;
        }

        .detail-value {
            font-size: 0.95rem;
        }

        .logout-btn {
            margin-top: auto;
            background-color: #e74c3c;
            color: white;
            border: none;
            padding: 10px;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.2s;
            font-weight: bold;
        }

        .logout-btn:hover {
            background-color: #c0392b;
        }

        .user-list {
            width: 250px;
            border-right: 1px solid #e0e0e0;
            background-color: #f8f9fa;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
        }

        .user-list-header {
            padding: 15px;
            border-bottom: 1px solid #e0e0e0;
            background-color: #ecf0f1;
            font-weight: bold;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .user-count {
            font-size: 0.8rem;
            color: #7f8c8d;
        }

        .user-item {
            padding: 12px 15px;
            cursor: pointer;
            border-bottom: 1px solid #e0e0e0;
            transition: background-color 0.2s;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .user-item:hover {
            background-color: #e9ecef;
        }

        .user-item.active {
            background-color: #e3f2fd;
            font-weight: bold;
        }

        .user-avatar {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            font-weight: bold;
            color: white;
        }

        .user-item-name {
            flex: 1;
        }

        .unread-count {
            background-color: #3498db;
            color: white;
            border-radius: 10px;
            padding: 2px 6px;
            font-size: 0.7rem;
        }

        .no-users {
            padding: 20px;
            text-align: center;
            color: #7f8c8d;
        }

        .chat-area {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: #f5f5f5;
        }

        .chat-header {
            padding: 15px;
            border-bottom: 1px solid #e0e0e0;
            background-color: white;
            font-weight: bold;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .chat-title {
            font-size: 1.1rem;
        }

        .chat-actions {
            display: flex;
            gap: 10px;
        }

        .messages {
            flex: 1;
            padding: 20px;
            overflow-y: auto;
            background-color: #f5f5f5;
        }

        .message {
            margin-bottom: 15px;
            max-width: 70%;
            position: relative;
        }

        .message.sent {
            margin-left: auto;
        }

        .message.received {
            margin-right: auto;
        }

        .message-bubble {
            padding: 12px 15px;
            border-radius: 18px;
            position: relative;
            word-break: break-word;
        }

        .message.sent .message-bubble {
            background-color: #3498db;
            color: white;
            border-bottom-right-radius: 0;
        }

        .message.received .message-bubble {
            background-color: white;
            border-bottom-left-radius: 0;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
        }

        .message-header {
            font-weight: bold;
            margin-bottom: 5px;
            font-size: 0.9em;
        }

        .message.sent .message-header {
            color: rgba(255, 255, 255, 0.8);
        }

        .message.received .message-header {
            color: #3498db;
        }

        .message-time {
            font-size: 0.7em;
            color: #7f8c8d;
            margin-top: 5px;
            text-align: right;
        }

        .message-input {
            padding: 15px;
            background-color: white;
            border-top: 1px solid #e0e0e0;
        }

        .input-group {
            display: flex;
            gap: 10px;
        }

        .input-group input {
            flex: 1;
            padding: 10px 15px;
            border: 1px solid #ddd;
            border-radius: 20px;
            outline: none;
        }

        .input-group input:focus {
            border-color: #3498db;
        }

        .input-group button {
            padding: 10px 20px;
            border: none;
            border-radius: 20px;
            background-color: #3498db;
            color: white;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .input-group button:hover {
            background-color: #2980b9;
        }

        .input-group button:disabled {
            background-color: #95a5a6;
            cursor: not-allowed;
        }

        .input-hint {
            font-size: 0.8rem;
            color: #7f8c8d;
            margin-top: 5px;
            padding-left: 10px;
        }

        .login-modal {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1000;
        }

        .login-form {
            background-color: white;
            padding: 30px;
            border-radius: 8px;
            width: 400px;
            max-width: 90%;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        .login-title {
            text-align: center;
            margin-bottom: 25px;
            color: #2c3e50;
        }

        .form-group {
            margin-bottom: 20px;
        }

        .form-group label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
        }

        .form-control {
            width: 100%;
            padding: 10px 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 1rem;
        }
        /* 大厅群聊项样式 */
        .lobby-item {
            border-bottom: 1px solid #e0e0e0;
            margin-bottom: 5px;
            background-color: #f8f9fa;
        }

        .lobby-item:hover {
            background-color: #e9ecef;
        }

        .lobby-item.active {
            background-color: #e3f2fd;
            font-weight: bold;
        }

        .lobby-avatar {
            background-color: #3498db !important;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
        }
        .btn-primary {
            width: 100%;
            padding: 12px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 1rem;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .btn-primary:hover {
            background-color: #2980b9;
        }

        .alert {
            padding: 10px 15px;
            border-radius: 4px;
            margin-bottom: 20px;
            font-size: 0.9rem;
        }

        .alert-danger {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
        .toast {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 12px 24px;
            border-radius: 8px;
            color: white;
            z-index: 10000;
            font-size: 14px;
            font-weight: 500;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            display: flex;
            align-items: center;
            animation: toast-in 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
            toast-out 0.5s ease 2.5s forwards;
            transform-origin: top right;
            max-width: 350px;
            line-height: 1.5;
        }

        /* 不同类型的 toast 颜色 */
        .toast-info {
            background-color: #3498db;
            border-left: 4px solid #2980b9;
        }

        .toast-success {
            background-color: #2ecc71;
            border-left: 4px solid #27ae60;
        }

        .toast-warning {
            background-color: #f39c12;
            border-left: 4px solid #d35400;
            color: #2c3e50;
        }

        .toast-error {
            background-color: #e74c3c;
            border-left: 4px solid #c0392b;
        }

        /* 图标样式（可选） */
        .toast::before {
            content: "";
            display: inline-block;
            width: 20px;
            height: 20px;
            margin-right: 12px;
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
        }

        .toast-info::before {
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z'/%3E%3C/svg%3E");
        }

        .toast-success::before {
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z'/%3E%3C/svg%3E");
        }

        .toast-warning::before {
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%232c3e50' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z'/%3E%3C/svg%3E");
        }

        .toast-error::before {
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z'/%3E%3C/svg%3E");
        }

        /* 动画效果 */
        @keyframes toast-in {
            0% {
                transform: translateX(100%) scale(0.7);
                opacity: 0;
            }
            100% {
                transform: translateX(0) scale(1);
                opacity: 1;
            }
        }

        @keyframes toast-out {
            0% {
                transform: translateX(0) scale(1);
                opacity: 1;
            }
            100% {
                transform: translateX(100%) scale(0.7);
                opacity: 0;
            }
        }

        /* 响应式调整 */
        @media (max-width: 600px) {
            .toast {
                top: 10px;
                right: 10px;
                left: 10px;
                max-width: calc(100% - 20px);
            }

            @keyframes toast-in {
                0% {
                    transform: translateY(-100%) scale(0.7);
                    opacity: 0;
                }
                100% {
                    transform: translateY(0) scale(1);
                    opacity: 1;
                }
            }

            @keyframes toast-out {
                0% {
                    transform: translateY(0) scale(1);
                    opacity: 1;
                }
                100% {
                    transform: translateY(-100%) scale(0.7);
                    opacity: 0;
                }
            }
        }
    </style>
</head>
<body>
<div id="app">
    <!-- 登录模态框 -->
    <div class="login-modal" v-if="showLoginModal">
        <div class="login-form">
            <h3 class="login-title">用户登录</h3>
            <div v-if="loginError" class="alert alert-danger">{{ loginError }}</div>
            <form @submit.prevent="handleLogin">
                <div class="form-group">
                    <label for="loginUser">用户名</label>
                    <input type="text" class="form-control" id="loginUser" v-model="loginUser" required>
                </div>
                <div class="form-group">
                    <label for="loginPassword">密码</label>
                    <input type="password" class="form-control" id="loginPassword" v-model="loginPassword" required>
                </div>
                <button type="submit" class="btn btn-primary">登录</button>
            </form>
        </div>
    </div>

    <!-- 主聊天界面 -->
    <div v-else class="app-container">
        <div class="chat-container">
            <!-- 用户信息面板 -->
            <div class="user-profile">
                <div class="profile-header">
                    <div class="avatar" :style="{ backgroundColor: getAvatarColor(currentUser) }">
                        {{ getInitials(currentUser) }}
                    </div>
                    <div class="user-name">{{ currentUser }}</div>
                    <div class="user-email" v-if="userInfo.email">{{ userInfo.email }}</div>
                    <div class="user-status">
                        <span class="status-indicator" :class="{ online: isConnected }"></span>
                        {{ isConnected ? '在线' : '离线' }}
                    </div>
                </div>

                <div class="profile-details" v-if="userInfo">
                    <div class="detail-item" v-if="userInfo.role">
                        <div class="detail-label">角色</div>
                        <div class="detail-value">{{ userInfo.role }}</div>
                    </div>
                    <div class="detail-item" v-if="userInfo.joinedAt">
                        <div class="detail-label">加入时间</div>
                        <div class="detail-value">{{ formatDate(userInfo.joinedAt) }}</div>
                    </div>
                    <div class="detail-item" v-if="userInfo.department">
                        <div class="detail-label">部门</div>
                        <div class="detail-value">{{ userInfo.department }}</div>
                    </div>
                </div>

                <button class="logout-btn" @click="logout">
                    <i class="fas fa-sign-out-alt"></i> 退出登录
                </button>
            </div>

            <!-- 用户列表 -->
            <div class="user-list">
                <div class="user-list-header">
                    <span>在线用户</span>
                    <span class="user-count">{{ onlineUsers.length }}人在线</span>
                </div>
                <!-- 添加返回大厅按钮 -->
                <div class="user-item lobby-item"
                     :class="{ active: !selectedUser }"
                     @click="returnToLobby()">
                    <div class="user-avatar lobby-avatar">
                        <i class="fas fa-users"></i>
                    </div>
                    <div class="user-item-name">大厅群聊</div>
                </div>
                
                <div v-if="onlineUsers.length === 0" class="no-users">
                    暂无其他在线用户
                </div>
                <div v-for="user in onlineUsers" :key="user"
                     class="user-item"
                     :class="{ active: selectedUser === user }"
                     @click="selectPrivateUser(user)">
                    <div class="user-avatar" :style="{ backgroundColor: getAvatarColor(user) }">
                        {{ getInitials(user) }}
                    </div>
                    <div class="user-item-name">{{ user }}</div>
                    <div v-if="privateMessages[user]?.length > 0" class="unread-count">
                        {{ privateMessages[user]?.length }}
                    </div>
                </div>
            </div>

            <!-- 聊天区域 -->
            <div class="chat-area">
                <div class="chat-header">
                    <div class="chat-title">
                        <span v-if="selectedUser">与 {{ selectedUser }} 的私聊</span>
                        <span v-else>群聊</span>
                    </div>
                    <div class="chat-actions">
                        <button class="btn btn-sm btn-outline-secondary" @click="clearChat">
                            清空聊天
                        </button>
                    </div>
                </div>

                <!-- 消息区域 -->
                <div class="messages" ref="messagesContainer">
                    <!-- 群聊消息 -->
                                       <div v-if="!selectedUser">
                                           <!-- 渲染历史消息 -->
                                           <div v-for="(msg, index) in historyMessages" :key="'history-' + index"
                                                class="message"
                                                :class="msg.user === currentUser ? 'sent' : 'received'">
                                               <div class="message-bubble">
                                                   <div class="message-header">{{ msg.user }}</div>
                                                   <div>{{ msg.message }}</div>
                                                   <div class="message-time">{{ msg.time }}</div>
                                               </div>
                                           </div>
                                           <!-- 渲染实时消息 -->
                                           <div v-for="(msg, index) in messages" :key="'realtime-' + index"
                                                class="message"
                                                :class="msg.user === currentUser ? 'sent' : 'received'">
                                               <div class="message-bubble">
                                                   <div class="message-header">{{ msg.user }}</div>
                                                   <div>{{ msg.text }}</div>
                                                   <div class="message-time">{{ msg.time }}</div>
                                               </div>
                                           </div>
                                       </div>

                    <!-- 私聊消息 -->
                    <div v-else>
                        <div v-for="(msg, index) in privateMessages[selectedUser]" :key="index"
                             class="message"
                             :class="msg.sender === currentUser ? 'sent' : 'received'">
                            <div class="message-bubble">
                                <div class="message-header">{{ msg.sender }}</div>
                                <div>{{ msg.text }}</div>
                                <div class="message-time">{{ msg.time }}</div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 消息输入框 -->
                <div class="message-input">
                    <!-- 群消息输入框 (当没有选中私聊用户时显示) -->
                    <div class="input-group" v-if="!selectedUser">
                        <input type="text"
                               class="form-control"
                               v-model="message"
                               @keyup.enter="sendMessage()"
                               placeholder="发送群消息..."
                               :disabled="!isConnected">
                        <button class="btn btn-primary sendMessage-btn"
                                @click="sendMessage()"
                                :disabled="!isConnected || !message.trim()">
                            发送
                        </button>
                    </div>

                    <!-- 私聊消息输入框 (当选中私聊用户时显示) -->
                    <div class="input-group" v-else>
                        <input type="text"
                               class="form-control"
                               v-model="privateMessage"
                               @keyup.enter="sendPrivateMessage()"
                               :placeholder="`发送给 ${selectedUser}...`"
                               :disabled="!isConnected">
                        <button class="btn btn-primary sendMessage-btn"
                                @click="sendPrivateMessage()"
                                :disabled="!isConnected || !privateMessage.trim()">
                            发送私信
                        </button>
                    </div>

                    <div class="input-hint" v-if="!isConnected">
                        <i class="fas fa-exclamation-circle"></i> 连接已断开，正在尝试重新连接...
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    const { createApp, ref, onMounted, nextTick } = Vue;

    const app = createApp({
        setup() {
            const showLoginModal = ref(false);
            const loginUser = ref('');
            const loginPassword = ref('');
            const loginError = ref('');
            const selectedUser = ref(null);
            const onlineUsers = ref([]);
            const currentUser = ref('');
            const userInfo = ref({});
            const message = ref('');
            const messages = ref([]);
            const historyMessages = ref([]);
            const privateMessage = ref('');
            const privateMessages = ref({});
            const isConnected = ref(false);
            const retryCount = ref(0);
            const maxRetries = 5;
            const messagesContainer = ref(null);
            let connection = null;



            async function fetchPrivateHistory(toUserId) {
                const token = localStorage.getItem('auth_token');
                const res = await fetch(`/api/chat/private/${toUserId}`, {
                    headers: {
                        Authorization: `Bearer ${token}`
                    }
                });

                if (!res.ok) {
                    console.error("无法获取聊天记录");
                    return;
                }

                const data = await res.json();

                // 确保私聊消息存储到正确的用户
                privateMessages.value[toUserId] = data.map(msg => ({
                    sender: msg.user,
                    text: msg.message,
                    time: msg.time
                }));
            }


            async function loadHistoryMessages() {
                const token = localStorage.getItem('auth_token');

                const response = await fetch("/api/chat/history", {
                    headers: {
                        Authorization: `Bearer ${token}`
                    }
                });
                const data = await response.json();
                
                historyMessages.value = data;
                console.log({historyMessages: historyMessages.value});
            }
            // 解析 JWT Token
            function parseJwt(token) {
                try {
                    const base64Url = token.split('.')[1];
                    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
                    const jsonPayload = decodeURIComponent(
                        window.atob(base64)
                            .split('')
                            .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
                            .join('')
                    );
                    return JSON.parse(jsonPayload);
                } catch (e) {
                    console.error("无法解析 JWT Token");
                    return {};
                }
            }

            // 获取用户名的首字母
            function getInitials(name) {
                if (!name) return '';
                const parts = name.split(' ');
                return parts.map(part => part[0]).join('').toUpperCase();
            }
            function returnToLobby() {
                selectedUser.value = null;
            }
            // 根据用户名生成头像颜色
            function getAvatarColor(name) {
                if (!name) return '#6c757d';
                const colors = [
                    '#3498db', '#2ecc71', '#e74c3c', '#f39c12',
                    '#9b59b6', '#1abc9c', '#d35400', '#34495e'
                ];
                const hash = name.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
                return colors[hash % colors.length];
            }

            // 格式化日期
            function formatDate(dateString) {
                if (!dateString) return '';
                const date = new Date(dateString);
                return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
            }


            // 滚动到消息底部
            function scrollToBottom() {
                nextTick(() => {
                    if (messagesContainer.value) {
                        messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
                    }
                });
            }

            // 检查token
            function checkTokenOnLoad() {
                const token = localStorage.getItem('auth_token');
                if (token) {
                    try {
                        const decoded = parseJwt(token);
                        userInfo.value = decoded;
                        currentUser.value = decoded.username || decoded.unique_name || decoded.sub;
                        showLoginModal.value = false;
                        connectSignalR();
                    } catch (e) {
                        localStorage.removeItem('auth_token');
                        showLoginModal.value = true;
                    }
                } else {
                    showLoginModal.value = true;
                }
            }

            // 登录处理
            async function handleLogin() {
                try {
                    const response = await fetch("/api/Auth/login", {
                        method: "POST",
                        headers: {
                            "Content-Type": "application/json"
                        },
                        body: JSON.stringify({
                            username: loginUser.value,
                            password: loginPassword.value
                        })
                    });

                    if (!response.ok) {
                        throw new Error("登录失败，请检查用户名或密码");
                    }

                    const result = await response.json();
                    const token = result.token;
                    const refreshToken = result.refreshToken;

                    localStorage.setItem('auth_token', token);
                    localStorage.setItem('refresh_token', refreshToken); // 👈 新增这一行

                    // 解析token获取用户信息
                    const decoded = parseJwt(token);
                    userInfo.value = decoded;
                    currentUser.value = decoded.username || decoded.unique_name || decoded.sub || loginUser.value;

                    loginUser.value = '';
                    loginPassword.value = '';
                    loginError.value = '';
                    showLoginModal.value = false;
                    connectSignalR();
                } catch (err) {
                    loginError.value = err.message;
                    console.error(err);
                }
            }

            // 连接SignalR
            function connectSignalR() {
                const token = localStorage.getItem('auth_token');

                console.log(`[运维日志] 开始建立 SignalR 连接，使用的 Token: ${token ? '存在' : '不存在'}`);

                connection = new signalR.HubConnectionBuilder()
                    .withUrl("/chathub", {
                        accessTokenFactory: () => token
                    })
                    .build();

                connection.onclose(async (error) => {
                    console.log(`[运维日志] SignalR 连接关闭，错误信息: ${error?.message}`);
                    isConnected.value = false;

                    if (error && error.message.includes('401')) {
                        console.log(`[运维日志] 401 错误，清除 Token 并显示登录模态框`);
                        localStorage.removeItem('auth_token');
                        showLoginModal.value = true;
                    } else {
                        console.log(`[运维日志] 尝试重新连接 SignalR`);
                        retryConnection();
                    }
                });

                connection.on("ReceiveMessage", function (fromUser, text) {
                    console.log(`[运维日志] 收到群聊消息，发送者: ${fromUser}, 内容: ${text}`);
                    messages.value.push({
                        user: fromUser,
                        text: text,
                        time: new Date().toLocaleTimeString()
                    });
                    scrollToBottom();
                });

                connection.on("ReceivePrivateMessage", function (fromUser, text) {
                    console.log(`[运维日志] 收到私聊消息，发送者: ${fromUser}, 内容: ${text}`);
                    const target = fromUser === selectedUser.value ? selectedUser.value : fromUser;

                    if (!privateMessages.value[target]) {
                        privateMessages.value[target] = [];
                    }

                    privateMessages.value[target].push({
                        sender: fromUser,
                        text: text,
                        time: new Date().toLocaleTimeString()
                    });

                    if (target === selectedUser.value) {
                        scrollToBottom();
                    }
                });

                connection.on("UpdateUserList", function (users) {
                    console.log(`[运维日志] 更新在线用户列表，当前在线用户: ${users.join(', ')}`);
                    onlineUsers.value = users;
                });

                connection.start()
                    .then(() => {
                        isConnected.value = true;
                        retryCount.value = 0;
                        console.log(`[运维日志] SignalR 连接成功`);
                        console.log(`[运维日志] 加载历史消息`);
                        loadHistoryMessages(); // 加载历史消息
                    })
                    .catch((err) => {
                        console.error(`[运维日志] SignalR 连接失败，错误信息: ${err.toString()}`);
                        if (err.toString().includes('401')) {
                            console.log(`[运维日志] 401 错误，清除 Token 并显示登录模态框`);
                            localStorage.removeItem('auth_token');
                            showLoginModal.value = true;
                        }
                    });
            }

            // 重试连接
            function retryConnection() {
                if (retryCount.value >= maxRetries) {
                    return;
                }

                retryCount.value++;
                const delay = Math.pow(2, retryCount.value) * 1000;

                setTimeout(() => {
                    connectSignalR();
                }, delay);
            }

            // 发送消息
            function sendMessage() {
                console.log('sendMessage');
                if (!isConnected.value) {
                    console.log('Debug: Connection is not established.');
                    return;
                }

                message.value = message.value.trim();
                console.log('Debug: Trimmed message:', message.value);

                if (!message.value) {
                    console.log('Debug: Message content is empty.');
                    return;
                }

                console.log(`[运维日志] 调用 connection.invoke("SendMessage")，参数:`, currentUser.value, message.value);
                connection.invoke("SendMessage", currentUser.value, message.value)
                    .then(() => {
                        console.log(`[运维日志] connection.invoke("SendMessage") 调用成功`);
                    })
                    .catch(function (err) {
                        console.error(`[运维日志] connection.invoke("SendMessage") 调用失败:`, err.toString());
                    });

                message.value = '';
                scrollToBottom();
                console.log('Debug: Scrolled to bottom after sending message.');
            }

            // 选择私聊用户
            function selectPrivateUser(user) {
                selectedUser.value = user;

                if (!privateMessages.value[user]) {
                    privateMessages.value[user] = [];
                }
                fetchPrivateHistory(user)
                scrollToBottom();
            }

            // 发送私聊消息
            function sendPrivateMessage() {
                console.log('sendPrivateMessage');
                if (!isConnected.value) {
                    return;
                }

                privateMessage.value = privateMessage.value.trim();

                if (!selectedUser.value) {
                    return;
                }

                if (!privateMessage.value) {
                    return;
                }

                console.log(`[运维日志] 调用 connection.invoke("SendPrivateMessage")，参数:`, selectedUser.value, privateMessage.value);
                connection.invoke("SendPrivateMessage", selectedUser.value, privateMessage.value)
                    .then(() => {
                        console.log(`[运维日志] connection.invoke("SendPrivateMessage") 调用成功`);
                    })
                    .catch(function (err) {
                        console.error(`[运维日志] connection.invoke("SendPrivateMessage") 调用失败:`, err.toString());
                    });

                const time = new Date().toLocaleTimeString();

                if (!privateMessages.value[selectedUser.value]) {
                    privateMessages.value[selectedUser.value] = [];
                }

                privateMessages.value[selectedUser.value].push({
                    sender: currentUser.value,
                    text: privateMessage.value,
                    time
                });

                privateMessage.value = '';
                scrollToBottom();
            }

            // 清空当前聊天
            function clearChat() {
                if (selectedUser.value) {
                    privateMessages.value[selectedUser.value] = [];
                } else {
                    messages.value = [];
                }
            }

            // 退出登录
            function logout() {
                if (connection && connection.state === signalR.HubConnectionState.Connected) {
                    connection.stop();
                }

                localStorage.removeItem('auth_token');
                messages.value = [];
                privateMessages.value = {};
                onlineUsers.value = [];
                currentUser.value = '';
                userInfo.value = {};
                showLoginModal.value = true;
            }

            // 初始化
            onMounted(() => {
                checkTokenOnLoad();
            });

            return {
                showLoginModal,
                loginUser,
                loginPassword,
                loginError,
                currentUser,
                userInfo,
                message,
                historyMessages,
                messages,
                isConnected,
                selectedUser,
                onlineUsers,
                privateMessage,
                privateMessages,
                messagesContainer,
                handleLogin,
                sendMessage,
                selectPrivateUser,
                sendPrivateMessage,
                returnToLobby,
                clearChat,
                logout,
                getInitials,
                getAvatarColor,
                formatDate
            };
        }
    });

    app.mount('#app');
</script>
</body>
</html>